package models

import (
	"os"
	"strings"

	"gitee.com/haodreams/godriver/opdb"
	"gitee.com/haodreams/godriver/opdb/opsql"
	"gitee.com/haodreams/golib/logs"
	"gitee.com/haodreams/libs/config"
	"gitee.com/haodreams/libs/ee"
	"gitee.com/haodreams/op_node/thirdparty"
	"gitee.com/hnxr_1/lib/openplant"
	"gitee.com/hnxr_1/nodex"
	"gorm.io/gorm"
	"gorm.io/gorm/schema"
)

type TaskDesc struct {
	Relation *nodex.Parent
	ID       *int //画布id
	Value    *float64
	Bad      *bool
	Err      *string
}

type OpenplantTask struct {
	tasks   []*Task
	mapTask map[string]*Task

	tasksDesc    []*TaskDesc
	opdb         *openplant.DB
	readValues   []string
	mapReadItem  map[string]*opdb.Real
	writeValues  []*opdb.Real
	mapWriteItem map[string]*opdb.Real

	mapItem map[string]*thirdparty.Item //内存测点

	enable bool
}

func (m *OpenplantTask) Setup() (err error) {
	opDsn := config.String("op.dsn")
	if opDsn == "" {
		return
	}
	op, err := gorm.Open(opsql.Open(opDsn), &gorm.Config{
		NamingStrategy: schema.NamingStrategy{
			SingularTable: true,
		},
	})
	if err != nil {
		return ee.New(err).Print(logs.CbWarn)
	}
	m.opdb = openplant.NewDB(op)
	m.mapReadItem = make(map[string]*opdb.Real)
	m.mapWriteItem = make(map[string]*opdb.Real)
	m.mapItem = make(map[string]*thirdparty.Item)
	m.enable = true

	err = m.LoadTask()
	if err != nil {
		ee.Print(err, logs.CbWarn)
	}

	return
}

func (m *OpenplantTask) LoadTask() (err error) {
	m.mapTask = make(map[string]*Task)
	path := NodePath + "openplant/"
	fs, err := os.ReadDir(path)
	if err != nil {
		return err
	}
	for _, f := range fs {
		if f.IsDir() {
			continue
		}
		if strings.HasSuffix(f.Name(), ".json") {
			task, err := parseToTask("openplant", path+f.Name())
			if err == nil {
				m.tasks = append(m.tasks, task)
				taskDesc := new(TaskDesc)
				taskDesc.Relation = &task.Relation
				taskDesc.Value = &task.Value
				taskDesc.Bad = &task.Bad
				taskDesc.Err = &task.Err
				m.tasksDesc = append(m.tasksDesc, taskDesc)
				name := strings.TrimSuffix(taskDesc.Relation.FileName, ".json")
				m.mapTask[name] = task
			}
		}
	}

	return
}

func (m *OpenplantTask) GetMemItem(name string) *thirdparty.Item {
	item := m.mapItem[name]
	if item != nil {
		return item
	}

	item = new(thirdparty.Item)
	item.Name = name
	m.mapItem[name] = item

	return item
}

func (m *OpenplantTask) GetOPValue(name string, isRead bool) *opdb.Real {
	name = strings.TrimSpace(name)
	if !m.checkName(name) {
		real := new(opdb.Real)
		real.Status = -1
		return real
	}
	if isRead {
		return m.AddReadItem(name)
	}
	return m.AddWriteItem(name)
}

func (m *OpenplantTask) checkName(name string) bool {
	ss := strings.Split(name, ".")
	return len(ss) == 3
}

/**
 * @description: 新增一个item
 * @param {*Item} item
 * @return {*}
 */
func (m *OpenplantTask) AddReadItem(name string) *opdb.Real {
	if !m.enable {
		real := new(opdb.Real)
		real.Status = -2
		return real
	}
	item, ok := m.mapReadItem[name]
	if ok && item != nil {
		return item
	}
	item = new(opdb.Real)
	item.Name = name
	item.Status = -1
	m.mapReadItem[item.Name] = item
	m.readValues = append(m.readValues, item.Name)
	return item
}

/**
 * @description: 新增一个item
 * @param {*Item} item
 * @return {*}
 */
func (m *OpenplantTask) AddWriteItem(name string) *opdb.Real {

	if !m.enable {
		real := new(opdb.Real)
		real.Status = -2
		return real
	}
	item, ok := m.mapWriteItem[name]
	if ok && item != nil {
		logs.Warn("写入测点存在冲突", name)
		return item
	}
	item = new(opdb.Real)
	item.Name = name
	item.Status = -1
	m.mapWriteItem[item.Name] = item
	m.writeValues = append(m.writeValues, item)
	return item
}

func (m *OpenplantTask) Run(now int64) (err error) {
	for _, task := range m.tasks {
		err = task.Run(now)
		if err != nil {
			logs.Warn(task.Relation.FileName, err)
		}
		task.Value, task.Bad = task.GetResult()
	}
	return
}

func (m *OpenplantTask) GetTaskData(name string) *Task {
	return m.mapTask[name]
}

/**
 * @description: 从麦杰库读取数据
 * @return {*}
 */
func (m *OpenplantTask) Read() (err error) {
	if !m.enable {
		return
	}
	rows, err := m.opdb.ReadValueByName(m.readValues)
	if err != nil {
		for _, val := range m.mapReadItem {
			val.Status = -1
		}
		return
	}
	for _, row := range rows {
		val, ok := m.mapReadItem[row.Name]
		if ok {
			*val = *row
		}
	}
	return
}

/**
 * @description:从麦杰库写入数据
 * @return {*}
 */
func (m *OpenplantTask) Write(now int64) (err error) {
	if !m.enable {
		return
	}
	for _, v := range m.writeValues {
		v.Time = now
	}
	return m.opdb.WriteValue(m.writeValues)
}
